package service

import (
	"os"
	"path"

	"gitee.com/linxing_3/sr-core/domain/service/srvctx"
	"gitee.com/linxing_3/sr-core/yal/ystr"
	"gitee.com/linxing_3/sr-core/yerr"
	"gitee.com/mkwchecking/sr-admin/apps/devtools/acl"
	"gitee.com/mkwchecking/sr-admin/apps/devtools/conf"
	"gitee.com/mkwchecking/sr-admin/apps/devtools/repo"
)

func NewClassGen(gen *repo.ClassGenRepo, table *repo.ModuleTable) *ClassGen {
	return &ClassGen{
		gen:   gen,
		table: table,
	}
}

type ClassGen struct {
	gen   *repo.ClassGenRepo
	table *repo.ModuleTable
}

// func (s *ClassGen) ClassGenAny(ctx srvctx.IContext, req *acl.ClassGenAnyReq) error {
// 	reflObj, err := yconv.GetObjectFields(req.Object, model.GAllInject{})
// 	if err != nil {
// 		return err
// 	}

// }

func (s *ClassGen) ClassGen(ctx srvctx.IContext, req *acl.ClassGenReq) error {
	tplArg, err := s.table.GetTplArg(req.Domain, req.ClassName)
	if err != nil {
		return err
	}

	fileMap, err := s.getTplOutFileMap(tplArg, req)
	if err != nil {
		return err
	}

	if !req.Force {
		for file := range fileMap {
			if f, err := os.Stat(file); err == nil && !f.IsDir() {
				return yerr.ErrDataExists.Errorf("%s file exists", file)
			}
		}
	}

	for file, content := range fileMap {
		if err := os.MkdirAll(path.Dir(file), os.ModePerm); err != nil {
			return err
		}

		if err := os.WriteFile(file, []byte(content), os.ModePerm); err != nil {
			return err
		}
	}

	return nil
}

func (s *ClassGen) DomainCheck(ctx srvctx.IContext, req *acl.DomainCheckReq) error {
	aimDomainDir := path.Join(conf.Config.Devtools.BackProjPath, "apps", req.Domain)
	if stat, err := os.Stat(aimDomainDir); err == nil && stat.IsDir() {
		return nil
	} else {
		return yerr.ErrDataNotfound.Errorf("domain %s not found", req.Domain)
	}
}

func (s *ClassGen) getTplOutFileMap(tplArg *acl.TplTable, req *acl.ClassGenReq) (map[string]string, error) {
	outputFiles := map[string]string{}
	backProjPath := conf.Config.Devtools.BackProjPath
	frontProjPath := conf.Config.Devtools.FrontProjPath

	classSnake := ystr.SnakeString(tplArg.ClassName)
	classCamel := ystr.CaptainLower(ystr.CamelString(tplArg.ClassName))

	s.gen.WithTplDir(conf.Config.Devtools.TemplateDir)

	if req.BackAcl {
		out, err := s.gen.ExecuteBackAcl(tplArg)
		if err != nil {
			return nil, err
		}

		outputFiles[path.Join(backProjPath, "apps", tplArg.DomainLower, "acl", classSnake+".g.go")] = out
	}

	if req.BackEntity {
		out, err := s.gen.ExecuteBackEntity(tplArg)
		if err != nil {
			return nil, err
		}

		outputFiles[path.Join(backProjPath, "apps", tplArg.DomainLower, "entity", classSnake+".g.go")] = out
	}

	if req.BackRepo {
		out, err := s.gen.ExecuteBackRepo(tplArg)
		if err != nil {
			return nil, err
		}
		outputFiles[path.Join(backProjPath, "apps", tplArg.DomainLower, "repo", classSnake+".g.go")] = out
	}

	if req.BackService {
		out, err := s.gen.ExecuteBackService(tplArg)
		if err != nil {
			return nil, err
		}
		outputFiles[path.Join(backProjPath, "apps", tplArg.DomainLower, "service", classSnake+".g.go")] = out
	}

	if req.BackHttpClient {
		out, err := s.gen.ExecuteBackHttpClient(tplArg)
		if err != nil {
			return nil, err
		}
		outputFiles[path.Join(backProjPath, "apps", tplArg.DomainLower, "adapter/http/client", classSnake+".g.go")] = out
	}

	if req.BackHttpRouter {
		out, err := s.gen.ExecuteBackHttpRouter(tplArg)
		if err != nil {
			return nil, err
		}
		outputFiles[path.Join(backProjPath, "apps", tplArg.DomainLower, "adapter/http/router", classSnake+".g.go")] = out
	}

	if req.BackApi {
		out, err := s.gen.ExecuteBackApi(tplArg)
		if err != nil {
			return nil, err
		}
		outputFiles[path.Join(backProjPath, "apps", tplArg.DomainLower, "adapter/http/api", classSnake+".g.go")] = out
	}

	if req.BackHttpTest {
		out, err := s.gen.ExecuteBackHttpTest(tplArg)
		if err != nil {
			return nil, err
		}
		outputFiles[path.Join(backProjPath, "apps", tplArg.DomainLower, "adapter/http/test", classSnake+".g.go")] = out
	}

	if req.FrontApi {
		out, err := s.gen.ExecuteFrontApi(tplArg)
		if err != nil {
			return nil, err
		}
		outputFiles[path.Join(frontProjPath, "src/views/domain", tplArg.DomainLower, "api", classCamel+".ts")] = out
	}

	if req.FrontView {
		out, err := s.gen.ExecuteFrontView(tplArg)
		if err != nil {
			return nil, err
		}
		outputFiles[path.Join(frontProjPath, "src/views/domain", tplArg.DomainLower, "views", classCamel, "index.vue")] = out
	}

	if req.FrontViewProvider {
		out, err := s.gen.ExecuteFrontViewProvider(tplArg)
		if err != nil {
			return nil, err
		}
		outputFiles[path.Join(frontProjPath, "src/views/domain", tplArg.DomainLower, "views", classCamel, "provider.ts")] = out
	}

	return outputFiles, nil
}
